// Copyright (c) 2009-2010, Jeremy Brewer
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

package galaxie500.util;

/**
 * Class holding various math static functions
 * 
 * @author Jeremy Brewer
 */
public class MathUtil {
  /**
   * Floating point equality comparison function. This is the preferred way to
   * check for equality among floating point numbers.
   * 
   * Adapted from code at the following URL:
   * 
   * @url 
   *      http://www.cygnus-software.com/papers/comparingfloats/Comparing%20floating
   *      %20point%20numbers.htm
   * 
   * @param a The first number
   * @param b The second number
   * @param maxRelativeError The maximum relative error threshold
   * @param maxAbsoluteError The maximum absolute error threshold
   * @return Whether a == b within the desired precision
   */
  public static boolean floatEqual(double a, double b,
                                   double maxRelativeError,
                                   double maxAbsoluteError) {
    if (Math.abs(a - b) < maxAbsoluteError) return true;
    double relativeError =
        (Math.abs(b) > Math.abs(a)) ? Math.abs((a - b) / b) :
                                      Math.abs((a - b) / a);
    return relativeError <= maxRelativeError;
  }

  /**
   * Returns x^2, faster than Math.pow(x, 2).
   * 
   * @param x The number to square
   * @return The value of x * x
   */
  public static double square(double x) {
    return x * x;
  }

  /**
   * Return x^3, faster than Math.pow(x, 3).
   * 
   * @param x The value to cube
   * @return The value of x * x * x
   */
  public static double cube(double x) {
    return x * x * x;
  }

  /**
   * Returns whether an integer is even.
   * 
   * @param x The value to test
   * @return Whether x is even
   */
  public static boolean isEven(int x) {
    return x % 2 == 0;
  }

  /**
   * Safely divides two integers to yield a double result. Returns a default
   * value in case of 0 division.
   * 
   * @param a The numerator
   * @param b The denominator
   * @param defaultValue The value to return if b == 0
   * @return a / b or defaultValue if b == 0
   */
  public static double safeDivide(int a, int b, double defaultValue) {
    return b == 0 ? defaultValue : (double) a / (double) b;
  }

  /**
   * Safely divide two doubles, returning a default value in case of zero
   * division.
   * 
   * @param a The numerator
   * @param b The denominator
   * @param defaultValue The value to return if b == 0
   * @return a / b or defaultValue if b == 0
   */
  public static double safeDivide(double a, double b, double defaultValue) {
    return b == 0.0 ? defaultValue : a / b;
  }

  /**
   * Safely divide two doubles such that infinity is never returned.
   * 
   * @param a The numerator
   * @param b The denominator
   * @return
   */
  public static double safeDivide(double a, double b) {
    return safeDivide(a, b, Math.signum(a) * Double.MAX_VALUE);
  }

  /**
   * Returns the minimum of 3 doubles.
   * 
   * @param a First param
   * @param b Second param
   * @param c Third param
   * @return The smallest of a, b, and c.
   */
  public static double min3(double a, double b, double c) {
    return Math.min(a, Math.min(b, c));
  }
}
